﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Web.UI;
using System.Xml;

namespace MyChart
{
    /// <summary>
    /// 简单图表控件抽象基类。
    /// </summary>
    public abstract class SimpleChart : FusionChart
    {
        #region 字段

        private bool _percentMode = false;

        private string _dataTextField = "";
        private string _dataValueField = "";

        SingleSeriesManager _itemManager;

        #endregion

        #region 属性

        /// <summary>
        /// 获取或设置展现数据项值的后缀文本
        /// 例：25%
        /// </summary>
        public override string NumberSuffix
        {
            get { return (_percentMode ? "%" : base.NumberSuffix); }
            set { base.NumberSuffix = value; }
        }

        /// <summary>
        /// 获取或设置一个值，表示是否启用百分比呈现模式
        /// </summary>
        public virtual bool PercentMode
        {
            get { return _percentMode; }
            set { _percentMode = value; }
        }

        /// <summary>
        /// 获取或设置要从数据源绑定到数据项集合文本域的字段名
        /// </summary>
        public virtual string DataTextField
        {
            get { return _dataTextField; }
            set { _dataTextField = value; }
        }

        /// <summary>
        /// 获取或设置要从数据源绑定到数据项集合值域的字段名
        /// </summary>
        public virtual string DataValueField
        {
            get { return _dataValueField; }
            set { _dataValueField = value; }
        }

        /// <summary>
        /// 获取或设置控件的数据项集合
        /// </summary>
        public virtual SingleSeriesManager ItemManager
        {
            get { return _itemManager; }
            set { _itemManager = value; }
        }

        #endregion

        #region 事件

        /// <summary>
        /// 控件绑定数据前事件
        /// </summary>
        new public virtual event EventHandler<FusionChartDataBindingEventArgs> DataBinding;

        /// <summary>
        /// 控件绑定数据后事件
        /// </summary>
        public virtual event EventHandler<SimpleChartDataBindedEventArgs> DataBinded;

        /// <summary>
        /// 控件绘制前事件
        /// </summary>
        public virtual event EventHandler<SimpleChartRenderingEventArgs> Rendering;

        #endregion

        #region 构造器

        /// <summary>
        /// 初始化 SimpleChart 类
        /// </summary>
        public SimpleChart()
        {
            _itemManager = new SingleSeriesManager(this);
        }

        #endregion

        #region 抽象方法

        /// <summary>
        /// 要求子类实现获取控件的 FusionChart 完整Xml配置字符串方法
        /// </summary>
        /// <returns>完整的Xml配置字符串</returns>
        public abstract string GetRenderHtml();

        #endregion

        #region 方法

        /// <summary>
        /// 获取控件对应的flash文件路径
        /// </summary>
        /// <returns>flash文件路径</returns>
        protected override string GetFlashPath()
        {
            //获取当前控件实例的具体类型，然后通过类型名找到配置节点并加载flash文件
            string type = this.GetType().FullName;
            XmlNodeList listNodes = FusionChart.MyChartConfig.DocumentElement.SelectNodes("/myChart/mappingGroup/mapping");
            foreach (XmlNode xmlNode in listNodes)
            {
                if (xmlNode.Attributes["type"] != null && xmlNode.Attributes["type"].Value == type)
                {
                    return xmlNode.Attributes["flash"].Value;
                }
            }
            throw (new Exception("没有找到控件'" + type + "'的flash路径映射节点。"));
        }

        /// <summary>
        /// 重写 System.Web.UI.Control 基类的 OnInit 初始化事件
        /// </summary>
        /// <param name="e">事件参数</param>
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            if (_itemManager != null)
            {
                _itemManager.Chart = this;
            }
        }

        /// <summary>
        /// 重写 System.Web.UI.Control 基类的 OnPreRender 绘制前事件
        /// </summary>
        /// <param name="e">事件参数</param>
        protected override void OnPreRender(EventArgs e)
        {
            if (!Page.ClientScript.IsClientScriptIncludeRegistered("MyChart"))
            {
                Page.ClientScript.RegisterClientScriptInclude("MyChart", Page.ClientScript.GetWebResourceUrl(this.GetType(), "MyChart.Resource.FusionCharts.js"));
            }

            base.OnPreRender(e);
        }

        /// <summary>
        /// 重写 System.Web.UI.Control 基类的 RenderControl 绘制控件方法
        /// </summary>
        /// <param name="writer">html绘制输出流</param>
        public override void RenderControl(HtmlTextWriter writer)
        {
            //触发控件绘制前事件
            if (Rendering != null)
            {
                SimpleChartRenderingEventArgs args = new SimpleChartRenderingEventArgs(_itemManager);
                Rendering(this, args);
            }

            base.RenderControl(writer);

            writer.Write(FusionRender.RenderChart(_blnZeroSum || _itemManager.IsEmpty, GetFlashPath(), "", FormatRenderHtml(GetRenderHtml()), ClientID, Width.ToString(), Height.ToString(), ItemManager.DictArguments, base.IsCustomRender));
        }

        /// <summary>
        /// 执行控件数据绑定
        /// </summary>
        public override void DataBind()
        {
            DataView view;

            //判断数据源是哪种类型
            if (DataSource == null)
            {
                return;
            }
            else if (DataSource is DataSet)
            {
                view = (DataSource as DataSet).Tables[0].DefaultView;
            }
            else if (DataSource is DataTable)
            {
                view = (DataSource as DataTable).DefaultView;
            }
            else if (DataSource is DataView)
            {
                view = DataSource as DataView;
            }
            else if (DataSource is MultiDimensionalDataSource)
            {
                view = (DataSource as MultiDimensionalDataSource).GetDataSource();
            }
            else
            {
                throw (new Exception("DataSource不是有效的数据源！"));
            }

            //触发数据绑定前事件
            if (DataBinding != null)
            {
                FusionChartDataBindingEventArgs args = new FusionChartDataBindingEventArgs(view);
                DataBinding(this, args);
            }

            _itemManager.Items.Clear();
            foreach (DataRowView drv in view)
            {
                ChartItem item = new ChartItem();
                item.Text = drv[_dataTextField].ToString();
                item.Value = drv[_dataValueField].ToString();
                item.Row = drv;
                _itemManager.Items.Add(item);
            }

            //触发数据绑定后事件
            if (DataBinded != null)
            {
                SimpleChartDataBindedEventArgs args = new SimpleChartDataBindedEventArgs(view, _itemManager);
                DataBinded(this, args);
            }
        }

        private bool _blnZeroSum = false;

        /// <summary>
        /// 获取控件的数据项集合的FusionChart Xml字符串
        /// </summary>
        /// <returns>控件的数据项集合的FusionChart Xml字符串</returns>
        protected string GetItemManagerXmlString()
        {
            //如果没有开启则直接返回_itemManager的xml字符串。
            //否则创建一个临时的单序列数据项集合
            //求所有数据项的值累加和，然后去除每个数据项的值得到百分比，并加到临时数据项集合中
            //最后返回临时数据项集合的xml字符串
            if (_percentMode)
            {
                SingleSeriesManager ssm = new SingleSeriesManager(this);
                double sum = 0;
                foreach (ChartItem item in _itemManager.Items)
                {
                    double tmp;
                    if (double.TryParse(item.Value, out tmp))
                    {
                        sum += tmp;
                    }
                }

                if (sum == 0)
                {
                    _blnZeroSum = true;
                }

                int iIndex = 0;
                double dUnlessLastScale = 0; //意图是：最后一个比例 = 1-当前的比例之和，这样不会造成例如3个33.33%加起来不等于100%的问题。
                foreach (ChartItem item in _itemManager.Items)
                {
                    iIndex++;
                    ChartItem ci = new ChartItem();
                    ci.Text = item.Text;
                    ci.Row = item.Row;
                    ci.Color = item.Color;
                    double tmp;
                    bool bParse = double.TryParse(item.Value, out tmp);
                    if (iIndex == _itemManager.Items.Count)
                    {
                        ci.Value = (1 - dUnlessLastScale).ToString();
                    }
                    else
                    {
                        if (bParse)
                        {
                            double dScale = Math.Round(tmp / sum, base.Decimals + 2);//这里加上2位的原因是我们现实的值是百分比的，所以加2个精确位
                            ci.Value = (sum == 0 ? (0).ToString() : (dScale).ToString());

                            dUnlessLastScale += dScale;
                        }
                    }
                    ssm.Items.Add(ci);
                }
                string sChartXML = ssm.GetXmlString();  //DictArguments是在执行这个方法后才被附值
                _itemManager.DictArguments = ssm.DictArguments;
                return sChartXML;
            }
            else
            {
                return _itemManager.GetXmlString();
            }
        }

        #endregion
    }
}
